#include <iostream>
#include <string.h>
#include <vector>
#include "RingQueue.h"
#include "LockFreeRingQueue.hpp"

#define LOGD(fmt, arg...) \
{\
    fprintf(stdout, "DEBUG %s, %s, line: %d, " fmt "\r\n", \
    __FILE__, __FUNCTION__, __LINE__, ##arg);\
    }

struct Point
{
    int iX = 0;
    int iY = 0;
    int iZ = 0;
};

void testInt()
{
    RingQueue<int> dataQueue;
    LOGD("queue capacity: %u, size: %u, empty: %d, full: %d.",  dataQueue.capacity(), dataQueue.size(), dataQueue.isEmpty(), dataQueue.isFull());

    dataQueue.pushBack(123);
    LOGD("pop data: %d.", dataQueue.popFront());
    dataQueue.popFront();
    dataQueue.popFront();
    LOGD("pop data: %d.", dataQueue.popFront());
    LOGD("pop data: %d.", dataQueue.popFront());

    dataQueue.pushBack(123);
    dataQueue.pushBack(234);
    dataQueue.pushBack(345);
    dataQueue.pushBack(456);
    LOGD("pop data: %d.", dataQueue.popFront());
    LOGD("pop data: %d.", dataQueue.popFront());
    LOGD("queue size: %u, empty: %d, full: %d.", dataQueue.size(), dataQueue.isEmpty(), dataQueue.isFull());

    for(size_t i = 0, size = dataQueue.capacity() - 2; i < size; ++i)
    {
        dataQueue.pushBack(i + 1);
    }
    LOGD("queue size: %u, empty: %d, full: %d.", dataQueue.size(), dataQueue.isEmpty(), dataQueue.isFull());

    for(size_t i = 0, size = dataQueue.capacity(); i < size; ++i)
    {
        LOGD("pop data: %d.", dataQueue.popFront());
    }
    LOGD("queue size: %u, empty: %d, full: %d.", dataQueue.size(), dataQueue.isEmpty(), dataQueue.isFull());
    return;
}

void testStruct()
{
    RingQueue<Point> dataQueue;
    LOGD("queue size: %u, empty: %d, full: %d.", dataQueue.size(), dataQueue.isEmpty(), dataQueue.isFull());

    Point point;
    point.iX = 0;
    point.iY = 1;
    point.iZ = 2;
    dataQueue.pushBack(point);
    LOGD("queue size: %u, empty: %d, full: %d.", dataQueue.size(), dataQueue.isEmpty(), dataQueue.isFull());
    LOGD("pop data: %d.", dataQueue.popFront().iY);
    LOGD("pop data: %d.", dataQueue.popFront().iZ);

    return;
}

#define LEN (3 * 1024 * 1024)
void testNoneLockRingQueue()
{
    char szData[LEN] = {0};
    for (size_t i = 0; i < LEN; ++i)
    {
        szData[i] = 'a';
    }

    std::string strData = std::string(szData, LEN);
    LockFreeRingQueue<std::string, 8> queue;

    // 写线程
    std::thread writer([&](){
        int count = 0;
        while (count < 1000) {
            queue.push(strData, true);
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }

        return;
    });

    // 读线程
    std::thread reader([&](){
        int count = 0;
        std::string item  = "";
        while (count < 1000) {
            item  = "";
            if (queue.pop(item, true)) {
                std::cout << "data length: " << item.length() << std::endl;
                ++count;
            } else {
                std::this_thread::yield();
            }
        }
        return;
    });

    writer.join();
    reader.join();

    return;
}

int main(int argc, char** argv)
{
    std::cout << "start............" << std::endl;

    //testInt();
    //testStruct();
    testNoneLockRingQueue();
    std::cout << "end............" << std::endl;
    getchar();

    return 0;
}
